/*
 * modsAX Javascript Library
 * modsAX.com 2009 squall
 * modsAX are licensed under a Creative Commons Attribution 3.0 license.
 * http://creativecommons.org/licenses/by/3.0/deed.ko
 * If you don't want to author Link
 * You must register. Join the modsAX license member then you free use modsAX
 * http://www.modsAX.com
 */

var modsTree = Class.create(modsAX, {
  version       : "modsTree V1.0",
  author        : "SQUALL",
  createDate    : "2009.09.28",
  lastModifyDate: "2010.04.23",
  initialize: function($super){
    $super();
    this.coverA = "href=\"#modsExceptionScript\"";
    this.config.easing = {open:{duraing:300, easing:"expoInOut"}, close:{duration:300, easing:"elasticOut"}};
    this.config.DBLclickable = true;
  },
  /* ------------------------------------------------------------------------------------------------------------------ */
  /* _set ~~~~~~ */
  setConfig: function(configs){
    var _self = this;
    jQuery.each(Object.keys(configs), function(i, n){ // update to {this.config}
      _self.config[n] = configs[n];
      if(n == "rootElementID")
        if($M(configs[n])){ // Element check
          jQuery("#"+configs[n]).attr("unselectable", "on");
          jQuery("#"+configs[n]).attr("align", "left");
        }
    });
    this.init();
  },
  init: function(){
    var rootOnclick = this.rootOnclick.bind(this);
    jQuery("#"+this.config.rootElementID).unbind("click");
    jQuery("#"+this.config.rootElementID).bind("click", function(event){
      rootOnclick(this, event);
    });

    //if(this.config.DBLclickable){
      var rootOndblclick = this.rootOndblclick.bind(this);
      jQuery("#"+this.config.rootElementID).unbind("dblclick");
      jQuery("#"+this.config.rootElementID).bind("dblclick", function(event){
        rootOndblclick(this, event);
      });
    //}

    if(this.config.quickMenu){
      var rootOncontextmenu = this.rootOncontextmenu.bind(this);
      jQuery("#"+this.config.rootElementID).unbind("contextmenu");
      jQuery("#"+this.config.rootElementID).bind("contextmenu", function(event){
        rootOncontextmenu(this, event);
      });
    }

    if(this.config.quickMenu){
      this.myQmenu = new modsQmenu();
      this.myQmenu.setConfig(this.config.quickMenu);
    }
  },
  load: function(objs){
    if(this.config.dataType == "script"){ //스크립트 지정 방식
      this.trees = this.uniqTree(objs); // convert tree
      this.insertTree(null, this.trees);
    }else{ // url load 방식
      this._setConfigLoad(objs); // config loader
      var url   = this._getUrl("load");
      var pars  = this._getPars();
      var onreq = this.responseData.bind(this, null);
      if(url == "") this.outMsg("You will set the Load URL");
      new modsreq(url, {pars:pars, onsucc:onreq});
    }

    if(this.config.drag){
      var onDrop = this.onDrop.bind(this);
      this.myDrager = new modsDrag();
      this.myDrager.setConfig({
        dragStage         : this.config.rootElementID,
        dragBoxClassName  : this.config.drag.dragBoxClassName,
        bedragClassName   : this.config.drag.bedragClassName,
        bedropClassName   : this.config.drag.bedropClassName,
        dragClassName     : this.config.drag.dragClassName,
        dropClassName     : this.config.drag.dragClassName,
        onDrag            : "",
        onDrop            : onDrop
      });
      this.myDrager.active();
    }
  },
  /* ------------------------------------------------------------------------------------------------------------------ */
  /* on observe method ~~~~~~ */
  rootOncontextmenu: function(element, event){
    if(!(event.target.tagName == "A")) return;
    var eA = event.target;
    if(!eA.id) return;
    var clickIDs = eA.id.split("_"); // 0 : rootElementID, 1:_id, 2:클릭위치

    if(clickIDs[0] == this.config.rootElementID){
      var clickLiID = clickIDs[0]+"_"+clickIDs[1];
      if(clickIDs[2] == "i"){ // 오픈시도
        this.objOpen(clickLiID, "", event);
      }else if(clickIDs[2] == "t"){ //클릭 시도
        this.objOpen(clickLiID, "onlyopen", event);
        this.objClick(clickLiID, event);
      }
      this.myQmenu.show({target:this.config.rootElementID, pointer:{x:event.pageX, y:event.pageY}, message:this._getObj(clickLiID)});
    }
  },
  rootOnclick: function(element, event){
    if(!(event.target.tagName == "A")) return;
    var eA = event.target;
    if(!eA.id) return;
    var clickIDs = eA.id.split("_"); // 0 : rootElementID, 1:_id, 2:클릭위치

    if(clickIDs[0] == this.config.rootElementID){
      var clickLiID = clickIDs[0]+"_"+clickIDs[1];
      if(clickIDs[2] == "i"){ // 오픈시도
        this.objOpen(clickLiID, "", event);
      }else if(clickIDs[2] == "t"){ //클릭 시도
        if(!this.config.DBLclickable){
          // dblclick 사용안함
          //닫힌 경우에만 열기 허용
          this.objOpen(clickLiID, "onlyopen", event);
        }
        this.objClick(clickLiID, event);
      }
    }
  },
  rootOndblclick: function(element, event){
    if(!(event.target.tagName == "A")) return;
    var eA = event.target;
    if(!eA.id) return;
    var clickIDs = eA.id.split("_"); // 0 : rootElementID, 1:_id, 2:클릭위치

    if(clickIDs[0] == this.config.rootElementID){
      var clickLiID = clickIDs[0]+"_"+clickIDs[1];
      if(clickIDs[2] == "i"){ // 무시

      }else if(clickIDs[2] == "t"){ //오픈 시도
        this.objOpen(clickLiID);
      }
    }
  },
  objClick: function(clickLiID, event){
    var clickDiv = $("#"+clickLiID+" > div");
    clickDiv.addClass("sted");
    if(this.selects != clickLiID && this.selects != "")
      if($M(this.selects))
        $("#"+this.selects+" > div").removeClass("sted");

    this.selects = clickLiID;
    if(this.config.onclick){
      var paObj = this._getObj(clickLiID);
      this.config.onclick(paObj, event);
    }
  },
  objOpen: function(clickLiID, att, event){
    // open child node
    var paObj = this._getObj(clickLiID);
    if(this.config.dataType == "script"){ //스크립트 지정 방식
      if(paObj._cn == 1){ //have child tree;
        if(paObj._op){
          if(att){ // !this.config.DBLclickable
          }else{
            this.removeTree(clickLiID, paObj.cn);
            paObj._op = false;
          }
        }else{
          this.insertTree(clickLiID, paObj.cn);
          paObj._op = true;
        }
      }else{
        if(att != "onlyopen") this.objClick(clickLiID, event);
      }
    }else{ // url load 방식
      if(paObj._cn == 1){ //have child tree;
        if(paObj._op){
          if(att){ // !this.config.DBLclickable
          }else{
            this.removeTree(clickLiID, paObj.cn);
            paObj._op = false;
          }
        }else{
          var url   = this._getUrl("load");
          var pars  = this._getPars(paObj);
          var onreq = this.responseData.bind(this, paObj);
          new modsreq(url, {pars:pars, onsucc:onreq});
          paObj._op = true;
        }
      }else{
        if(att != "onlyopen") this.objClick(clickLiID, event);
      }
    }
  },
  /* ------------------------------------------------------------------------------------------------------------------ */
  /* class method ~~~~~~ */
  responseData: function(_parent, req){
    var res = req;
    if(res.result == "ok"){
      if(!_parent){
        this.trees = this.uniqTree(res.datas); // convert tree
        this.insertTree(null, this.trees);
      }else{
        _parent.cn = this.uniqTree(res.datas, _parent._id);
        //부모 노드 취하기
        var objID = this.config.rootElementID+"_"+_parent._id;
        this.insertTree(objID, res.datas);
      }
    }
  },
  insertTree: function(_parent, _obj){
    var coverA = this.coverA;
    var dragClassName = (this.config.drag) ? this.config.drag.dragClassName : "";
    if(_parent == null) _parent = this.config.rootElementID;

    if(_parent == this.config.rootElementID){
      var myUL = $("<ul class='rootUL'></ul>");
      _parent = "#"+_parent;
    }else{
      var myUL = $("<ul id='"+_parent.id+"_s'></ul>");
      jQuery("#"+_parent+" > div").addClass("open");
      _parent = "#"+_parent;
    }
    myUL.css("display", "none");

    var l = _obj.length;
    var s = 0;

    while(s < l){
      var etags = [];
      var objID = this.config.rootElementID+"_"+_obj[s]._id;
      var objClass = "nd";
      var dragClass = "";
      if(_obj[s]._cn) objClass += " havecn";
      if(_obj[s]._op) objClass += " open";
      if(_obj[s]._sl){
        objClass += " sted";
        this.selects = objID;
      }
      if(dragClassName != "") dragClass += " "+dragClassName;

      etags.push("<li id=\""+objID+"\"><div class=\""+objClass+"\">");
      etags.push("<a "+coverA+" id=\""+objID+"_i\" class=\"i\">-</a>");
      etags.push("<a "+coverA+" id=\""+objID+"_t\" class=\"t "+_obj[s].fm+dragClass+"\" title=\""+_obj[s].nm.dec().replace(/\"/g, "''")+"\">"+_obj[s].nm.dec()+"</a>");
      etags.push("</div><div class=\"sp\"></div>");
      if(_obj[s]._op && _obj[s]._cn){ //자식 개체 확인
        etags.push(this.getSubTree(_obj[s], _obj[s].cn));
      }
      etags.push("</li>");
      myUL.append(etags.join(''));
      s++;
    }
    jQuery(_parent).append(myUL);
    
    var config = this.config;
    myUL.slideDown({duration:this.config.easing.open.duration, easing:this.config.easing.open.easing, complete:function(){
      if(config.onOpen) config.onOpen({parent:_parent, obj:_obj});
    }});
    if(this.selects) $("#"+this.selects).children().addClass("sted");
  },
  getSubTree: function(_paObj, _obj){
    var coverA = this.coverA;
    var paobjID = this.config.rootElementID+"_"+_paObj._id+"_s";
    var etags = [];
    etags.push("<ul id=\""+paobjID+"\">");
    var l = _obj.length;
    var s = 0;
    while(s < l){
      var objID = this.config.rootElementID+"_"+_obj[s]._id;
      var objClass = "nd";
      if(_obj[s]._cn) objClass += " havecn";
      if(_obj[s]._op) objClass += " open";
      if(_obj[s]._sl){
        objClass += " sted";
        this.selects = objID;
      }

      etags.push("<li id=\""+objID+"\"><div class=\""+objClass+"\">");
      etags.push("<a "+coverA+" id=\""+objID+"_i\" class=\"i\">-</a>");
      etags.push("<a "+coverA+" id=\""+objID+"_t\" class=\"t "+_obj[s].fm+"\" title=\""+_obj[s].nm.dec().replace(/\"/g, "''")+"\">"+_obj[s].nm.dec()+"</a>");
      etags.push("</div><div class=\"sp\"></div>");
      if(_obj[s]._op){ //자식 개체 확인
        etags.push(this.getSubTree(_obj[s].cn));
      }
      etags.push("</li>");
      s++;
    }
    etags.push("</ul>");
    return etags.join('');
  },
  removeTree: function(_parent, _obj){
    //자식 개체 찾기
    var myTarget = jQuery("#"+_parent+" > ul").children();
    jQuery("#"+_parent+" > div").removeClass("open");
    
    if(mods.browser.browser == "ie" && mods.browser.version < 8){
      myTarget.remove();
    }else{
      myTarget.slideUp({duration:this.config.easing.close.duration, easing:this.config.easing.close.easing, complete:function(){
        myTarget.remove();
      }});
    }
  },
  onInsert: function(req){
    var coverA = this.coverA;
    var Obj = req.target, adder = req.adder, callBack = req.callBack;
    var reID = this.config.rootElementID;
    var paobjID = reID+"_"+Obj._id;

    if(!adder){
      alert("adder 개체가 없습니다.");
      return;
    }

    var new_id = 0;
    if(Obj.cn) new_id = Obj.cn.length;

    var objID = paobjID+"-"+new_id;
    var inputID = objID+"_input";
    adder._id = objID.replace(reID+"_", "");
    var objClass = "nd";

    var etags = [];
    etags.push("<li id=\""+objID+"\"><div class=\""+objClass+"\">");
    etags.push("<a "+coverA+" id=\""+objID+"_i\" class=\"i\">-</a>");
    etags.push("<a "+coverA+" id=\""+objID+"_t\" class=\"t "+adder.fm+"\"><input type=\"text\" name=\"modifyer\" value=\""+adder.nm+"\" id=\""+inputID+"\"></a>");
    etags.push("</div><div class=\"sp\"></div>");
    etags.push("</li>");
    if($M(paobjID+"_s")) jQuery("#"+paobjID+"_s").append(etags.join(''));
    else jQuery("#"+paobjID).append("<ul id=\""+paobjID+"_s\">"+etags.join('')+"</ul>");
    
    var inputObj = jQuery("#"+inputID);
    jQuery("#"+inputID).css({width:inputObj.width()-8+"px"});

    //enter esc blur - observe init
    inputObj.unbind("keyup");
    inputObj.unbind("blur");

    var insertE = this.insertE.bind(this);
    inputObj.bind("keyup", function(event){insertE(event, Obj, adder, callBack);});
    inputObj.bind("blur", function(event){insertE(event, Obj, adder, callBack);});

    var insertReady = this.insertReady.bind(this);
    setTimeout(function(){ insertReady({inputID:inputID}); }, 100);
  },
  insertReady: function(req){
    var inputID = req.inputID;
    jQuery("#"+inputID).select();
  },
  insertE: function(event, Obj, adder, callBack){
    var reID = this.config.rootElementID;
    var objID = reID+"_"+adder._id;
    var inputID = reID+"_"+adder._id+"_input";
    var inputObj = jQuery("#"+inputID);
    if(event.type == "blur" || (event.type == "keyup" && event.keyCode == mods.Event.KEY_RETURN)){
      inputObj.unbind("keyup");
      inputObj.unbind("blur");
      adder.nm = inputObj.val().enc();
      if(callBack) callBack({result:"insert", target:Obj, insertObj:adder});
      else this.insert({result:true, target:Obj, insertObj:adder});
    }else{
      if(event.keyCode == mods.Event.KEY_ESC){
        inputObj.unbind("keyup");
        inputObj.unbind("blur");
        if(Obj.cn) jQuery("#"+objID).remove();
        else jQuery("#"+reID+"_"+Obj._id+"_s").remove();
        if(callBack) callBack({result:"cancle", target:Obj});
      }
    }
  },
  insert: function(req){
    var Obj = req.target, result = req.result, adder = req.insertObj;
    var reID = this.config.rootElementID;
    var objID = reID+"_"+adder._id+"_t";
    var inputID = reID+"_"+adder._id+"_input";
    var inputObj = jQuery("#"+inputID);
    if(result){
      //push Object
      if(Obj.cn) Obj.cn.push(adder);
      else{
        Obj.cn = [];
        Obj.cn.push(adder);
        //부모개체 클래스 추가
        Obj._cn = 1;
        Obj._op = true;
        var paobjID = reID+"_"+Obj._id;
        var paobj_div =  jQuery("#"+paobjID+" > div");
        paobj_div.addClass("havecn");
        paobj_div.addClass("open");
      }
      inputObj.unbind("keyup");
      inputObj.unbind("blur");
      jQuery("#"+objID).html(adder.nm.dec());
    }else{
      inputObj.unbind("keyup");
      inputObj.unbind("blur");
      if(Obj.cn) jQuery("#"+objID).remove();
      else jQuery("#"+reID+"_"+Obj._id+"_s").remove();
    }
  },
  onModify: function(req){
    var Obj = req.target, callBack = req.callBack;
    var reID = this.config.rootElementID;
    var objID = reID+"_"+Obj._id+"_t";
    var inputID = reID+"_"+Obj._id+"_input";
    jQuery("#"+objID).html("<input type=\"text\" name=\"modifyer\" value=\"\" id=\""+inputID+"\">");

    var inputObj = jQuery("#"+inputID);
    inputObj.val(Obj.nm.dec());
    var insertReady = this.insertReady.bind(this);
    setTimeout(function(){ insertReady({inputID:inputID}); }, 100);
    inputObj.css({width:inputObj.width()-8+"px"});

    //enter esc blur - observe init
    inputObj.unbind("keyup");
    inputObj.unbind("blur");

    var modify = this.modify.bind(this);
    inputObj.bind("keyup", function(event){modify(event, Obj, callBack);});
    inputObj.bind("blur", function(event){modify(event, Obj, callBack);});
  },
  modify: function(event, Obj, callBack){
    var reID = this.config.rootElementID;
    var objID = reID+"_"+Obj._id+"_t";
    var inputID = reID+"_"+Obj._id+"_input";
    var inputObj = jQuery("#"+inputID);

    if(event.type == "blur" || (event.type == "keyup" && event.keyCode == mods.Event.KEY_RETURN)){
      var oldText = Obj.nm;
      Obj.nm = inputObj.val().enc();
      inputObj.unbind("keyup");
      inputObj.unbind("blur");
      jQuery("#"+objID).html(Obj.nm.dec());
      if(callBack) callBack({result:"change", target:Obj, prevnm:oldText});
    }else{
      if(event.keyCode == mods.Event.KEY_ESC){
        inputObj.unbind("keyup");
        inputObj.unbind("blur");
        jQuery("#"+objID).html(Obj.nm.dec());
        if(callBack) callBack({result:"cancle", target:Obj});
      }
    }
  },
  cancelModify: function(req){
    var Obj = req.target, nm = req.prevnm;
    var reID = this.config.rootElementID;
    var objID = reID+"_"+Obj._id+"_t";
    Obj.nm = nm;
    jQuery("#"+objID).html(Obj.nm.dec());
  },
  onDel: function(req){
    var Obj = req.target, callBack = req.callBack;
    var ans = confirm("선택된 개체를 삭제하시겠습니까? ");
    if(ans){
      if(callBack) callBack({result:"delete", target:Obj});
      else this.del({target:Obj, result:true});
    }
  },
  del: function(req){
    var Obj = req.target, result = req.result;
    var reID = this.config.rootElementID;
    var objID = reID+"_"+Obj._id;
    if(result){
      Obj._isDel = true;
      this.selects = "";
      jQuery("#"+objID).remove();
    }else{
      return;
    }
  },
  onMove: function(req){

  },
  move: function(req){

  },
  onDrop: function(req){
    if(this.config.drag.onDrop) this.config.drag.onDrop(req);
  },
  scrollToSelect: function(){
    //alert($M(this.selects));
    if($M(this.selects)) jQuery("#"+this.selects).scrollToDiv({left:0, top:-50});
  }
});